package com.nidu.demo.app.oatuh2;

import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.nidu.demo.common.constants.Constants;
import com.nidu.demo.auth.api.OAuth2Api;
import com.nidu.demo.oauth2.dto.OAuth2AccessTokenCO;
import com.nidu.demo.oauth2.dto.OAuth2ApproveCO;
import com.nidu.demo.oauth2.dto.OAuth2AuthorizeCmd;
import com.nidu.demo.oauth2.dto.OAuth2GrantCmd;
import com.nidu.demo.oauth2.util.OAuth2Utils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;

@Tag(name = "管理后台 - OAuth2.0 授权")
@RestController
@RequestMapping("/oauth2")
@Validated
@Slf4j
@RequiredArgsConstructor
public class OAuth2Controller {

    private final OAuth2Api oAuth2Api;

    @PostMapping("/authorize")
    @Operation(summary = "申请授权", description = "适合 authorization_code 授权码模式，implicit 简化模式")
    @Parameters({
            @Parameter(name = "grant_type", description = "授权类型", example = "code"),
            @Parameter(name = "client_code", description = "客户端编码", example = "cola"),
            @Parameter(name = "redirect_uri", description = "重定向URI"),
            @Parameter(name = "scope", description = "授权范围"),
            @Parameter(name = "approve", description = "用户是否接受授权"),
            @Parameter(name = "state", description = "状态")
    })
    public SingleResponse<String> authorize(@RequestParam("grant_type") String grantType,
                                            @RequestParam("client_code") String clientCode,
                                            @RequestParam("redirect_uri") String redirectUri,
                                            @RequestParam(value = "scope", required = false) String scope,
                                            @RequestParam(value = "approve") Boolean approve,
                                            @RequestParam(value = "state", required = false) String state) {
        // 构建授权请求
        OAuth2AuthorizeCmd authorizeCmd = new OAuth2AuthorizeCmd();
        authorizeCmd.setGrantType(grantType);
        authorizeCmd.setClientCode(clientCode);
        authorizeCmd.setClientSecret(null);
        authorizeCmd.setRedirectUri(redirectUri);
        authorizeCmd.setScopes(StrUtil.isEmpty(scope) ? Constants.DEFAULT_AUTH_SCOPES : StrUtil.split(scope, ','));
        authorizeCmd.setApproved(approve);
        authorizeCmd.setState(state);

        // 获取授权码或访问令牌
        return oAuth2Api.authorize(authorizeCmd);
    }

    @GetMapping("/authorize")
    @Operation(summary = "获取授权信息", description = "适合 code 授权码模式，或者 implicit 简化模式；在 sso.vue 单点登录界面被【提交】调用")
    public SingleResponse<OAuth2ApproveCO> getAuthorize(HttpServletRequest request){
        // 从Basic认证头中获取客户端凭据
        String[] clientCredentials = OAuth2Utils.getClientCredentials(request);
        String clientCode = clientCredentials[0];
        String clientSecret = clientCredentials[1];

        return oAuth2Api.getAuthorize(clientCode, clientSecret);
    }

    @PostMapping("/token")
    @PermitAll
    @Operation(summary = "获得访问令牌", description = "适合 authorization_code 授权码模式，password 密码模式，client_credentials 客户端模式，refresh_token 刷新令牌模式")
    @Parameters({
            @Parameter(name = "grant_type", description = "授权类型", example = "authorization_code"),
            @Parameter(name = "code", description = "授权码，grant_type=authorization_code 时必填"),
            @Parameter(name = "redirect_uri", description = "重定向URI，grant_type=authorization_code 时必填"),
            @Parameter(name = "username", description = "用户名，grant_type=password 时必填"),
            @Parameter(name = "password", description = "密码，grant_type=password 时必填"),
            @Parameter(name = "scope", description = "授权范围"),
            @Parameter(name = "refresh_token", description = "刷新令牌，grant_type=refresh_token 时必填")
    })
    public SingleResponse<OAuth2AccessTokenCO> getAccessToken(HttpServletRequest request,
                                                             @RequestParam("grant_type") String grantType,
                                                             @RequestParam(value = "code", required = false) String code,
                                                             @RequestParam(value = "redirect_uri", required = false) String redirectUri,
                                                             @RequestParam(value = "username", required = false) String username,
                                                             @RequestParam(value = "password", required = false) String password,
                                                             @RequestParam(value = "scope", required = false) String scope,
                                                             @RequestParam(value = "refresh_token", required = false) String refreshToken) {

        // 从Basic认证头中获取客户端凭据
        String[] clientCredentials = OAuth2Utils.getClientCredentials(request);
        String clientCode = clientCredentials[0];
        String clientSecret = clientCredentials[1];

        // 构建授权请求
        OAuth2GrantCmd grantCmd = new OAuth2GrantCmd();
        grantCmd.setGrantType(grantType);
        grantCmd.setClientCode(clientCode);
        grantCmd.setClientSecret(clientSecret);
        grantCmd.setCode(code);
        grantCmd.setRedirectUri(redirectUri);
        grantCmd.setUsername(username);
        grantCmd.setPassword(password);
        grantCmd.setScopes(StrUtil.isEmpty(scope) ? Constants.DEFAULT_AUTH_SCOPES :StrUtil.split(scope, ','));
        grantCmd.setRefreshToken(refreshToken);

        // 获取访问令牌
        return oAuth2Api.grantToken(grantCmd);
    }

    @GetMapping("/check-token")
    @Operation(summary = "校验访问令牌")
    @Parameter(name = "token", description = "访问令牌")
    public SingleResponse<OAuth2AccessTokenCO> checkToken(HttpServletRequest request, @RequestParam("token") String token) {
        // 从Basic认证头中获取客户端凭据
        String[] clientCredentials = OAuth2Utils.getClientCredentials(request);
        String clientId = clientCredentials[0];
        String clientSecret = clientCredentials[1];

        return oAuth2Api.checkAccessToken(clientId, clientSecret, token);
    }

    @DeleteMapping("/token")
    @PermitAll
    @Operation(summary = "删除访问令牌")
    @Parameter(name = "token", description = "访问令牌", example = "biu")
    public Response revokeToken(HttpServletRequest request, @RequestParam("token") String token) {
        // 从Basic认证头中获取客户端凭据
        String[] clientCredentials = OAuth2Utils.getClientCredentials(request);
        String clientId = clientCredentials[0];
        String clientSecret = clientCredentials[1];

        // 删除访问令牌
         return  oAuth2Api.removeAccessToken(clientId, clientSecret, token);
    }

}